package log

import (
	"flag"
	"github.com/natefinch/lumberjack"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"os"
	"time"
)

var zapLogger *zap.SugaredLogger
var debug bool

type logger struct {
	*zap.SugaredLogger
}

func init() {
	flag.BoolVar(&debug, "debug", false, "调试模式")
	flag.Parse()
	zapLogger = initLogger(1, true)
}

func New(callerSkip int, line bool) *logger {
	l := initLogger(callerSkip, line)
	return &logger{l}
}

func createLogsDir() {
	_, err := os.Stat("./logs")
	if err != nil && os.IsNotExist(err) {
		err = os.Mkdir("./logs", os.ModePerm)
		if err != nil {
			panic("logs文件夹创建失败，将无法创建日志")
		}
	}
}

func initLogger(l int, line bool) *zap.SugaredLogger {
	createLogsDir()
	writeSyncers := getLogWriter()
	encoder := getEncoder()
	atomicLevel := zap.NewAtomicLevel()
	atomicLevel.SetLevel(zap.DebugLevel)
	core := zapcore.NewCore(encoder, zapcore.NewMultiWriteSyncer(writeSyncers...), atomicLevel)

	var logger *zap.Logger
	if line {
		logger = zap.New(core, zap.AddCaller(), zap.AddCallerSkip(l))
	} else {
		logger = zap.New(core)
	}
	return logger.Sugar()
}

func getEncoder() zapcore.Encoder {
	encoderConfig := zap.NewProductionEncoderConfig()
	encoderConfig.EncodeTime = timeEncoder
	encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
	encoderConfig.EncodeCaller = zapcore.ShortCallerEncoder
	return zapcore.NewConsoleEncoder(encoderConfig)
}

func getLogWriter() []zapcore.WriteSyncer {
	date := time.Now().Format("2006-01-02")
	lumberJackLogger := &lumberjack.Logger{
		Filename:   "./logs/" + date + ".log",
		MaxSize:    128,
		MaxBackups: 30,
		MaxAge:     30,
		Compress:   false,
	}
	writers := []zapcore.WriteSyncer{zapcore.AddSync(lumberJackLogger)}
	if debug {
		writers = append(writers, zapcore.AddSync(os.Stdout))
	}
	return writers
}

func timeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
	layout := "2006-01-02 15:04:05"
	type appendTimeEncoder interface {
		AppendTimeLayout(time.Time, string)
	}

	if enc, ok := enc.(appendTimeEncoder); ok {
		enc.AppendTimeLayout(t, layout)
		return
	}

	enc.AppendString(t.Format(layout))
}

func Debug(args ...interface{}) {
	if debug {
		zapLogger.Debug(args...)
	}
}

func Debugw(msg string, args ...interface{}) {
	if debug {
		zapLogger.Errorw(msg, args...)
	}
}

func Debugf(format string, args ...interface{}) {
	if debug {
		zapLogger.Debugf(format, args...)
	}
}

func Info(args ...interface{}) {
	zapLogger.Info(args...)
}

func Infow(msg string, args ...interface{}) {
	zapLogger.Infow(msg, args...)
}

func Infof(format string, args ...interface{}) {
	zapLogger.Infof(format, args...)
}

func Fatal(args ...interface{}) {
	zapLogger.Fatal(args...)
}

func Fatalw(msg string, args ...interface{}) {
	zapLogger.Fatalw(msg, args...)
}

func Fatalf(format string, args ...interface{}) {
	zapLogger.Fatalf(format, args...)
}

func Error(args ...interface{}) {
	zapLogger.Error(args...)
}

func Errorw(msg string, args ...interface{}) {
	zapLogger.Errorw(msg, args...)
}

func Errorf(format string, args ...interface{}) {
	zapLogger.Errorf(format, args...)
}

func Warn(args ...interface{}) {
	zapLogger.Warn(args...)
}

func Warnw(msg string, args ...interface{}) {
	zapLogger.Warnw(msg, args...)
}

func Warnf(format string, args ...interface{}) {
	zapLogger.Warnf(format, args...)
}

func AsyncDebug(args ...interface{}) {
	if debug {
		go zapLogger.Debug(args...)
	}
}

func AsyncDebugw(msg string, args ...interface{}) {
	if debug {
		go zapLogger.Errorw(msg, args...)
	}
}

func AsyncDebugf(format string, args ...interface{}) {
	if debug {
		go zapLogger.Debugf(format, args...)
	}
}

func AsyncInfo(args ...interface{}) {
	go zapLogger.Info(args...)
}

func AsyncInfow(msg string, args ...interface{}) {
	go zapLogger.Infow(msg, args...)
}

func AsyncInfof(format string, args ...interface{}) {
	go zapLogger.Infof(format, args...)
}

func AsyncFatal(args ...interface{}) {
	go zapLogger.Fatal(args...)
}

func AsyncFatalw(msg string, args ...interface{}) {
	go zapLogger.Fatalw(msg, args...)
}

func AsyncFatalf(format string, args ...interface{}) {
	go zapLogger.Fatalf(format, args...)
}

func AsyncError(args ...interface{}) {
	go zapLogger.Error(args...)
}

func AsyncErrorw(msg string, args ...interface{}) {
	go zapLogger.Errorw(msg, args...)
}

func AsyncErrorf(format string, args ...interface{}) {
	go zapLogger.Errorf(format, args...)
}

func AsyncWarn(args ...interface{}) {
	go zapLogger.Warn(args...)
}

func AsyncWarnw(msg string, args ...interface{}) {
	go zapLogger.Warnw(msg, args...)
}

func AsyncWarnf(format string, args ...interface{}) {
	go zapLogger.Warnf(format, args...)
}

func (this *logger) Debug(args ...interface{}) {
	if debug {
		this.SugaredLogger.Debug(args...)
	}
}

func (this *logger) Debugw(msg string, args ...interface{}) {
	if debug {
		this.SugaredLogger.Errorw(msg, args...)
	}
}

func (this *logger) Debugf(format string, args ...interface{}) {
	if debug {
		this.SugaredLogger.Debugf(format, args...)
	}
}

func (this *logger) Info(args ...interface{}) {
	this.SugaredLogger.Info(args...)
}

func (this *logger) Infow(msg string, args ...interface{}) {
	this.SugaredLogger.Infow(msg, args...)
}

func (this *logger) Infof(format string, args ...interface{}) {
	this.SugaredLogger.Infof(format, args...)
}

func (this *logger) Fatal(args ...interface{}) {
	this.SugaredLogger.Fatal(args...)
}

func (this *logger) Fatalw(msg string, args ...interface{}) {
	this.SugaredLogger.Fatalw(msg, args...)
}

func (this *logger) Fatalf(format string, args ...interface{}) {
	this.SugaredLogger.Fatalf(format, args...)
}

func (this *logger) Error(args ...interface{}) {
	this.SugaredLogger.Error(args...)
}

func (this *logger) Errorw(msg string, args ...interface{}) {
	this.SugaredLogger.Errorw(msg, args...)
}

func (this *logger) Errorf(format string, args ...interface{}) {
	this.SugaredLogger.Errorf(format, args...)
}

func (this *logger) Warn(args ...interface{}) {
	this.SugaredLogger.Warn(args...)
}

func (this *logger) Warnw(msg string, args ...interface{}) {
	this.SugaredLogger.Warnw(msg, args...)
}

func (this *logger) Warnf(format string, args ...interface{}) {
	this.SugaredLogger.Warnf(format, args...)
}

func (this *logger) AsyncDebug(args ...interface{}) {
	if debug {
		go this.Debug(args...)
	}
}

func (this *logger) AsyncDebugw(msg string, args ...interface{}) {
	if debug {
		go this.Errorw(msg, args...)
	}
}

func (this *logger) AsyncDebugf(format string, args ...interface{}) {
	if debug {
		go this.Debugf(format, args...)
	}
}

func (this *logger) AsyncInfo(args ...interface{}) {
	go this.Info(args...)
}

func (this *logger) AsyncInfow(msg string, args ...interface{}) {
	go this.Infow(msg, args...)
}

func (this *logger) AsyncInfof(format string, args ...interface{}) {
	go this.Infof(format, args...)
}

func (this *logger) AsyncFatal(args ...interface{}) {
	go this.Fatal(args...)
}

func (this *logger) AsyncFatalw(msg string, args ...interface{}) {
	go this.Fatalw(msg, args...)
}

func (this *logger) AsyncFatalf(format string, args ...interface{}) {
	go this.Fatalf(format, args...)
}

func (this *logger) AsyncError(args ...interface{}) {
	go this.Error(args...)
}

func (this *logger) AsyncErrorw(msg string, args ...interface{}) {
	go this.Errorw(msg, args...)
}

func (this *logger) AsyncErrorf(format string, args ...interface{}) {
	go this.Errorf(format, args...)
}

func (this *logger) AsyncWarn(args ...interface{}) {
	go this.Warn(args...)
}

func (this *logger) AsyncWarnw(msg string, args ...interface{}) {
	go this.Warnw(msg, args...)
}

func (this *logger) AsyncWarnf(format string, args ...interface{}) {
	go this.Warnf(format, args...)
}
